采用迁移学习进行物体识别
山东理工大学 数学院 周世祥 shixiangbupt@qq.com
- 什么是迁移学习
站在巨人的肩上,“举一反三”,“触类旁通”,学会了C语言,也很快就学会了matlab,异曲同工。
把一个领域的知识,迁移到另一个领域,基于共享参数的迁移学习,以经典的卷积网络为基础,通过修改一个已经训练好的深度卷积网络的最后几层连接层,再使用对特定问题而建立的小数据集进行训练,以使其适用于一个新问题。
案例:对AlexNet网络进行改进,并用样本数据进行训练,实现对输入图像的识别。
%% 程序说明
% 实例
% 功能:基于共享参数的迁移学习的原理,对AlexNet进行改进,并用样本数据进行训练,实现对输入图像的识别
第二天再试试
% 作者:zhaoxch_mail@sina.com
% 注:本程序主要是用于说明基于迁移学习的原理,如何将已训练好的经典网络进行改进并进行训练,请重点关注步骤3、步骤4。
%% 步骤1:加载图像数据,并将其划分为训练集和验证集
imds = imageDatastore('MerchData', ...
'IncludeSubfolders',true, ...
'LabelSource','foldernames');
[imdsTrain,imdsValidation] = splitEachLabel(imds,0.7,'randomized');
numTrainImages = numel(imdsTrain.Labels);
idx = randperm(numTrainImages,16);
I = readimage(imdsTrain,idx(i));
% 加载alexnet网络(注:该网络需要提前下载,当输入下面命令时按要求下载即可)
layersTransfer = net.Layers(1:end-3);
numClasses = numel(categories(imdsTrain.Labels));
% 构建新的网络,保留AlexNet倒数第三层之前的网络,在此之后重新添加了全连接
layersTransfer % 保留AlexNet倒数第三层之前的网络
fullyConnectedLayer(numClasses) % 将新的全连接层的输出设置为训练数据中的种类
softmaxLayer % 添加新的Softmax层
classificationLayer ]; % 添加新的分类层
inputSize = net.Layers(1).InputSize;
augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain);
augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);
options = trainingOptions('sgdm', ...
'InitialLearnRate',0.00005, ...
'Shuffle','every-epoch', ...
'ValidationData',augimdsValidation, ...
'ValidationFrequency',3, ...
'Plots','training-progress');
netTransfer = trainNetwork(augimdsTrain,layers,options);
在单 GPU 上训练。
正在初始化输入数据归一化。
|=============================================================================|
| 轮 | 迭代 | 经过的时间 | 小批量准确度 | 验证准确度 | 小批量损失 | 验证损失 | 基础学习率 |
| | | (hh:mm:ss) | | | | | |
|=============================================================================|
| 1 | 1 | 00:00:04 | 20.00% | 10.00% | 3.5665 | 2.4579 | 5.0000e-05 |
| 1 | 3 | 00:00:04 | 6.67% | 25.00% | 4.5968 | 1.9925 | 5.0000e-05 |
| 2 | 6 | 00:00:05 | 26.67% | 50.00% | 2.9358 | 1.2960 | 5.0000e-05 |
| 3 | 9 | 00:00:05 | 40.00% | 70.00% | 1.8389 | 0.8930 | 5.0000e-05 |
| 4 | 12 | 00:00:06 | 40.00% | 80.00% | 2.4903 | 0.6268 | 5.0000e-05 |
| 5 | 15 | 00:00:06 | 86.67% | 85.00% | 0.5530 | 0.4274 | 5.0000e-05 |
| 6 | 18 | 00:00:06 | 86.67% | 95.00% | 0.5176 | 0.2976 | 5.0000e-05 |
| 7 | 21 | 00:00:07 | 86.67% | 95.00% | 0.3129 | 0.2067 | 5.0000e-05 |
| 8 | 24 | 00:00:07 | 93.33% | 100.00% | 0.2362 | 0.1526 | 5.0000e-05 |
| 9 | 27 | 00:00:07 | 93.33% | 100.00% | 0.1893 | 0.1197 | 5.0000e-05 |
| 10 | 30 | 00:00:08 | 100.00% | 100.00% | 0.0172 | 0.1009 | 5.0000e-05 |
|=============================================================================|
[YPred,scores] = classify(netTransfer,augimdsValidation);
idx = randperm(numel(imdsValidation.Files),4);
I = readimage(imdsValidation,idx(i));
YValidation = imdsValidation.Labels;
accuracy = mean(YPred == YValidation)
confusionchart(YValidation,YPred)
ans =
ConfusionMatrixChart - 属性:
NormalizedValues: [5×5 double]
ClassLabels: [5×1 categorical]
显示 所有属性
预训练好的Alex net网络的最后3层原本为用对1000个类别的物体进行识别,新的分类问题必须调整这3层。
先从预训练网络中取出除最后这三层外的所有层,然后用一个全连接层,一个softmax层和一个分类层替换最后3层。
由于AlexNet需要输入图像大小为227*227*3像素,因此还需要对训练图像的大小及验证数据的图像大小不同用函数augmentedImageDatastore()进行批量调整。
创建混淆矩阵:confusionchart()
矩阵行对应真实类,列对应预测类,对角线对应正确分类的个数,非对角线对应错误分类的个数。
心理学上,对某一项技能的学习能对其他技能产生积极的影响,迁移学习效应,人工智能研究领域之一。
卷积神经网络在进行物体识别过程中,可以自动提取特征并根据特征进行分类。
仿生学上,模仿大脑皮层工作原理的深度神经网络,卷积神经网络提取的特征是一层层抽象的,越是底层的特征越基本,底层的卷积层学习到角点,边缘,颜色,纹理等共性特征,越是高层越抽象越复杂,到了顶层附近学习到了特征可以大概描述一个物体了,这样的抽象特征又称语义特征。
在一些任务中,可用于训练的数据样本很少,如果从头训练一个卷积神经网络模型,效果不是很好,此时,可利用别人已经训练好的卷积神经网络模型,然后尝试改变该模型语义层的参数即可。
前面是共性,后面是个性,从统计意义上讲。
采用Deep Network Designer实现卷积网络设计
matlab中提供了一个便于设计,查看,检验深度网络的工具Deep network designer.
有两种打开方式,在命令窗口中,输入代码:
第二种方式:
用菜单方式,从APP中打开
下面的案例,构建一个卷积网络,实现对输入的含有数字0~9的二值图像28*28进行分类,并计算分类的准确率。
网络架构
输入:28*28像素,1个通道
卷积1:卷积核大小3*3,个数为32个,0填充方式(same)
批量归一化层1:加快训练时网络收敛速度;
非线性激励函数1:用ReLU 函数
池化层1:最大池化,2*2,步长1
卷积2:3*3,个数为32个,0填充方式(same)
批量归一化层2:
非线性激励函数2:用ReLU 函数
池化层1:最大池化,2*2,步长2
全连接层2:输出为10个
softmax层:得出全连接层每一个输出的概率
分类层:根据概率判断类别
步骤
步骤1:从模块库中将Image input layer模块拖到操作区中,单击该模块,在右侧属性显示区中进行参数设置,将其设置为输入图像大小28*28,1个通道。
步骤2:从模块库中将Convolution2DLayer模块拖到操作区中,单击该模块,在右侧属性显示区中对其进行参数设置,将其设置为:卷积核大小为3*3,卷积核的个数为32(每个卷积核1个通道),卷积的方式采用零填充方式,即same方式,其他采用默认设置。
步骤3:从模块库中将BatchNormalizationLayer拖到操作区中,单击该模块,在右侧属性显示区中对其进行参数设置,一般采用默认。
步骤4:从模块库中将ReLULayer模块拖到操作区中。
步骤5:从模块库中将MaxPooling2DLayer模块拖到操作区中,单击该模块,在右侧属性显示区中对其进行参数设置,将其设置为:池化区域为2*2,步长为1,其他采用默认设置。
步骤6:按第1到5步的方式,构建卷积层2,批量归一化层2,非线性激活函数2,最大池化层2,参数见前一节。
步骤7:从模块库中将FullyConnectedLayer模块拖到操作区中,单击该模块,在右侧属性显示区中对其进行参数设置,将其设置为:输出的个数10个,其他采用默认的设置。
步骤8:从模块库中将SoftmaxLayer拖到操作区中。
步骤9:从模块库中将ClassificationOutputLayer拖到操作区;
步骤10:将各层顺序依次连接;
步骤11:单击控制面板上的Analyze按钮,对所设计的网络进行检查,检查结果如图。
步骤12:单击导出Export,会将网络导出到工作区workspace,并默认名layers_1
步骤13:对于导出到工作区的卷积神经网络,在工作区中将其选中,通过右键快捷菜单将其重命名为covnet1
对网络进行训练与验证
训练方法为'sgdm',初始学习率为0.0005,最大轮数为6,每轮训练都随机打乱数据,验证频率为30次/轮。
在配置过程中,将'Verbose'设置为true,所以该网络的训练核验证过程也在命令窗口中显示。
%% 步骤1:加载图像样本数据,并显示其中的部分图像
digitDatasetPath = fullfile(matlabroot,'toolbox','nnet','nndemos', ...
'nndatasets','DigitDataset');
imds = imageDatastore(digitDatasetPath, ...
'IncludeSubfolders',true,'LabelSource','foldernames');
perm = randperm(10000,20);
imshow(imds.Files{perm(i)});
%% 步骤2:将加载的图像样本分为训练集和测试集(注:在本例中,训练集的数量为750幅,剩余的为测试集)
[imdsTrain,imdsValidation] = splitEachLabel(imds,numTrainFiles,'randomize');
options = trainingOptions('sgdm', ...
'InitialLearnRate',0.0005, ...
'Shuffle','every-epoch', ...
'ValidationData',imdsValidation, ...
'ValidationFrequency',30, ...
'Verbose',true, ... %显示训练过程
'Plots','training-progress');
net = trainNetwork(imdsTrain,covnet1,options);
在单 GPU 上训练。
正在初始化输入数据归一化。
|=============================================================================|
| 轮 | 迭代 | 经过的时间 | 小批量准确度 | 验证准确度 | 小批量损失 | 验证损失 | 基础学习率 |
| | | (hh:mm:ss) | | | | | |
|=============================================================================|
| 1 | 1 | 00:00:04 | 7.03% | 9.56% | 3.0360 | 2.8614 | 0.0005 |
| 1 | 30 | 00:00:06 | 54.69% | 51.04% | 1.5394 | 1.4985 | 0.0005 |
| 1 | 50 | 00:00:07 | 57.81% | | 1.2810 | | 0.0005 |
| 2 | 60 | 00:00:08 | 69.53% | 63.52% | 1.0615 | 1.1669 | 0.0005 |
| 2 | 90 | 00:00:10 | 72.66% | 70.16% | 1.0254 | 0.9953 | 0.0005 |
| 2 | 100 | 00:00:10 | 78.91% | | 0.9027 | | 0.0005 |
| 3 | 120 | 00:00:11 | 74.22% | 74.52% | 0.8409 | 0.8648 | 0.0005 |
| 3 | 150 | 00:00:13 | 81.25% | 78.84% | 0.7043 | 0.7388 | 0.0005 |
| 4 | 180 | 00:00:15 | 90.63% | 82.28% | 0.4792 | 0.6454 | 0.0005 |
| 4 | 200 | 00:00:15 | 82.03% | | 0.5725 | | 0.0005 |
| 4 | 210 | 00:00:16 | 86.72% | 84.96% | 0.4985 | 0.5688 | 0.0005 |
| 5 | 240 | 00:00:18 | 89.06% | 88.00% | 0.4597 | 0.4966 | 0.0005 |
| 5 | 250 | 00:00:18 | 88.28% | | 0.5131 | | 0.0005 |
| 5 | 270 | 00:00:19 | 92.19% | 89.64% | 0.4281 | 0.4395 | 0.0005 |
| 6 | 300 | 00:00:21 | 94.53% | 91.04% | 0.3613 | 0.3951 | 0.0005 |
| 6 | 330 | 00:00:23 | 92.19% | 91.72% | 0.3565 | 0.3614 | 0.0005 |
| 6 | 348 | 00:00:24 | 95.31% | 92.52% | 0.2662 | 0.3416 | 0.0005 |
|=============================================================================|
%% 步骤4:将训练好的网络用于对新的输入图像进行分类,并计算准确率
YPred = classify(net,imdsValidation);
YValidation = imdsValidation.Labels;
accuracy = sum(YPred == YValidation)/numel(YValidation)
accuracy =
0.926000000000000

在命令行中运行效果图:
accuracy =
0.938000000000000
采用Deep Network Designer实现迁移学习
调整网络结构
步骤1:加载预训练AlexNet网络
net= alexnet
net =
SeriesNetwork - 属性:
Layers: [25×1 nnet.cnn.layer.Layer]
InputNames: {'data'}
OutputNames: {'output'}
步骤2:将网络导入Deep Network Designer设计器
命令行窗口中输入以下代码
deepNetworkDesigner %在命令行中操作
按Import按钮导入刚刚加载的网络,如图所示,单击OK。
可以看到整个网络结构以可视化的形式呈现在设计区中,每个彩色矩阵块代表一层,右侧显示网络属性。
迁移学习官方案例参考
https://ww2.mathworks.cn/help/deeplearning/ug/transfer-learning-with-deep-network-designer.html